package com.ruantong.dingtalk.ding.attendance;

import com.dingtalk.api.response.OapiAttendanceListResponse;
import com.ruantong.dingtalk.ding.openapi.AttendanceApi;
import com.ruantong.dingtalk.model.DingAttnUserResult;
import com.ruantong.dingtalk.service.DingAttnUserResultService;
import com.ruantong.dingtalk.service.DingUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * @description:同步钉钉考勤数据
 * @author: jh.chen
 * @time: 2020/11/15 18:23
 */
@Slf4j
@Component
public class SynchronizeAttendanceDataFromDing {

    @Autowired
    private AttendanceApi attendanceApi;
    @Autowired
    private DingAttnUserResultService dingAttnUserResultService;
    @Autowired
    private DingUserService dingUserService;

    private static final Long MAX_SIZE = 50L;

    private static List<DingAttnUserResult> resultList = null;

    private static final Integer DEFAULT_MAX_SYNC_DAYS = 31;

    private static final Integer DEFAULT_SYNC_DAYS = 1;

    public void firstSyncWhenInit() {
        Long attnNum = dingAttnUserResultService.countAll();
        //第一次全量同步,默认同步到31天之前
        if (attnNum == 0) {
            log.info("first time SynchronizeAttendanceData is begin!");
            startJob(DEFAULT_MAX_SYNC_DAYS);
        }
    }

    public void startJob(Integer daysAgo) {
        log.info("start SynchronizeAttendanceData job,to get last {} days data!", daysAgo);
        if (daysAgo == null) {
            daysAgo = DEFAULT_SYNC_DAYS;
        }
        //获取以前考勤结果
        getResultList(daysAgo);
        //插入
        insertAttnRecord();
    }

    /**
     * 同步考勤数据,几天前至前一天的数据,如传3就是3天前到昨天，传1就是昨天的数据
     * 由于钉钉接口限制，建议不要回归太久，不然会被限制接口调用频率
     *
     * @Param: [daysAgo] 距今多少天
     * @Param: [userIdList] userId
     * @Return: void
     */
    public void getResultList(Integer daysAgo) {
        List<String> userIdList = dingUserService.getUserIdList();
        log.info("userId size for sync attn:{}", userIdList.size());
        //初始化,默认每人一天打卡两次
        resultList = new ArrayList<>(userIdList.size() * 2);
        //取时间范围内的所有数据,这里按天来多次取,避免一次返回太多数据
        for (Integer i = 0; i < daysAgo; i++) {
            log.info("sync {} day ago data", (i + 1));
            LocalDate now = LocalDate.now();
            LocalDate getAttnDate = now.minusDays(i);
            getAttnOneDayData(userIdList, getAttnDate);
        }

    }

    /**
     * 根据ids获取某天一天的考勤数据,ids大小不限制
     *
     * @param: [ids, beginDateTime, endDateTime]
     * @return: void
     */
    private void getAttnOneDayData(List<String> ids, LocalDate oneDate) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        LocalDateTime beginOneDateTime = LocalDateTime.of(oneDate.getYear(), oneDate.getMonth(),
                oneDate.getDayOfMonth(), 0, 0, 0);
        LocalDateTime endOneDateTime = LocalDateTime.of(oneDate.getYear(), oneDate.getMonth(),
                oneDate.getDayOfMonth(), 23, 59, 59);
        //id集合总大小
        int size = ids.size();
        //游标指针差，代表一次请求的最多id数量
        int indexLast = MAX_SIZE.intValue();
        //ids集合需要拆几次发送
        int iLimit = size / indexLast;
        //实际请求钉钉api的id集合
        List<String> limitIds = null;
        //方便计算
        int index = 1;
        //sub参数
        int subLimit = 0;
        int beginIndex = 0;
        for (int i = 0; i < (iLimit + 1); i++) {
            subLimit = indexLast * index > size ? size : indexLast * index;
            limitIds = ids.subList(beginIndex, subLimit);
            beginIndex = subLimit;
            log.info("beginIndex{},sublimit:{},beginOneDateTime:{},endOneDateTime:{},subList limitIds:{}",
                    i * subLimit, subLimit, beginOneDateTime, endOneDateTime, limitIds);
            getAttnDayData(limitIds, beginOneDateTime, endOneDateTime);
            index++;
        }
    }

    /**
     * 获取指定id的一定时间段内的考勤数据,id不能超过50个
     *
     * @param: [ids, beginDateTime, endDateTime]
     * @return: void
     */
    private void getAttnDayData(List<String> ids, LocalDateTime beginDateTime, LocalDateTime endDateTime) {
        if (ids.size() > MAX_SIZE) {
            log.warn("id size should less than 50.");
            return;
        }
        log.info("this req send ids:{}", ids);
        List<String> attnUserId = new ArrayList<>(ids.size());
        attnUserId.addAll(ids);
        Integer pageIndex = 0;
        for (; ; pageIndex++) {
            OapiAttendanceListResponse uerAttnResult = attendanceApi.getUerAttnResult(beginDateTime, endDateTime, attnUserId,
                    pageIndex.longValue(), MAX_SIZE);
            if (uerAttnResult == null) {
                break;
            }
            List<OapiAttendanceListResponse.Recordresult> recordResults = uerAttnResult.getRecordresult();
            if (recordResults == null || recordResults.size() == 0) {
                break;
            }
            recordResults.forEach(recordResult -> {
                DingAttnUserResult dingAttnUserResult = new DingAttnUserResult();
                BeanUtils.copyProperties(recordResult, dingAttnUserResult);
                //这个值只能手动插入
                dingAttnUserResult.setAttnId(recordResult.getId());
                resultList.add(dingAttnUserResult);
            });
        }
    }

    //插入db
    private void insertAttnRecord() {
        ListIterator<DingAttnUserResult> iterator = resultList.listIterator();
        while (iterator.hasNext()) {
            DingAttnUserResult attnUserResult = iterator.next();
            dingAttnUserResultService.insert(attnUserResult);
        }
    }
}
